/*
 *	actors.h - Game actors.
 *
 *  Copyright (C) 1998-1999  Jeffrey S. Freedman
 *  Copyright (C) 2000-2001  The Exult Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifndef INCL_ACTORS
#define INCL_ACTORS	1

#include "contain.h"
#include "utils.h"		// This is only included for Log2...
#include "flags.h"
#include "ready.h"

class Image_window;
class Game_window;
class Npc_actor;
class Actor_action;
class Schedule;
class Schedule_change;
class Monster_info;
class Monster_actor;
class Weapon_info;
class Dead_body;
class Npc_timer_list;
class Frames_sequence;
class Animator;
class Actor_attributes;

/*
 *	An actor:
 */
class Actor : public Container_game_object, public Time_sensitive
	{
	static Actor *editing;		// NPC being edited by ExultStudio.
protected:
	std::string name;			// Its name.
	int usecode;			// # of usecode function.
	bool usecode_assigned;		// Usecode # explicitly assigned.
	std::string usecode_name;		// Name of usecode fun explicitly assigned.
	bool unused;			// If npc_num > 0, this NPC is unused
					//   in the game.
	short npc_num;			// # in Game_window::npcs list, or -1.
	short face_num;			// Which shape for conversations.
	short party_id;			// Index in party, or -1.
	int properties[12];		// Properties set/used in 'usecode'.
	Actor_attributes *atts;		// Generic atts. (for new games/mods).
	unsigned char temperature;	// Measure of coldness (0-63).
	short shape_save;		// Our old shape, or -1.
	short oppressor;		// NPC ID (>= 0) of oppressor, or -1.
	Game_object *target;		// Who/what we're attacking.
	short casting_mode;		//For displaying casting frames.
	int casting_shape;	//Shape of casting frames.
	// These 2 are set by the Usecode function 'set_to_attack':
	Game_object *target_object;
	Tile_coord target_tile;
	int attack_weapon;
public:
	enum Attack_mode {		// Setting from gump.+++++Save/restore.
		nearest = 0,
		weakest = 1,		// Attack weakest.
		strongest = 2,
		berserk = 3,		// Always attack, never retreat.
		protect = 4,		// Protect NPC with halo.
		defend = 5,
		flank = 6,		// Attempt to attack from side.
		flee = 7,
		random = 8,		// Choose target at random.
		manual = 9
		};
	enum Casting_mode {
		not_casting = 0,		// The NPC is not casting.
		init_casting = 1,		// When set, the next usecode script will
					// display casting frames (shape 859).
		show_casting_frames = 2	// Used for displaying the casting frames.
					// Also flags that the when the script finishes, the
					// casting frames should be disabled.
		};
protected:
					// Party positions
	const static short party_pos[4][10][2];

	Attack_mode attack_mode;
					// A frame sequence for each dir.:
	static Frames_sequence *avatar_frames[4];
	static Frames_sequence *npc_frames[4];
	Frames_sequence **frames;
					// Draw weapon in hand
	void paint_weapon();
	unsigned char schedule_type;	// Schedule type (Schedule_type).
	Tile_coord schedule_loc;	// Location (x,y) of Shedule
	unsigned char next_schedule;	// Used so correct schedule type 
					//   will be saved
	Schedule *schedule;		// Current schedule.
	bool dormant;			// I.e., off-screen.
	bool hit;			// Just hit in combat.
	bool combat_protected;		// 'Halo' on paperdoll screen.
	bool user_set_attack;		// True if player set attack_mode.
	short alignment;		// 'Feelings' towards Ava. See below.
	Game_object *spots[18];		// Where things can go.  See 'Spots'
					//   below for description.
	bool two_handed;		// Carrying a two-handed item.
	bool two_fingered;		// Carrying gauntlets (both fingers)
	bool use_scabbard;		// Carrying an item in scabbard (belt, back 2h, shield).
	bool use_neck;			// Carrying cloak (amulet, cloak)
	unsigned char light_sources;	// # of light sources readied.
	unsigned char usecode_dir;	// Direction (0-7) for usecode anim.

	unsigned type_flags:32;	// 32 flags used in movement among other things
	unsigned char  gear_immunities;	// Damage immunities granted by gear.
	unsigned short gear_powers;		// Other powers granted by gear.

	unsigned char ident;

	int	skin_color;
	Actor_action *action;		// Controls current animation.
	std::vector<Actor_action *> deletedactions;		// Halted actions.
	int frame_time;			// Time between frames in msecs.  0 if
					//   actor not moving.
	int step_index;			// Index into walking frames, 1 1st.
	int qsteps;				// # steps since last quake.

	Npc_timer_list *timers;		// Timers for poison, hunger, etc.
	Rectangle weapon_rect;		// Screen area weapon was drawn in.
	long rest_time;			// # msecs. of not doing anything.
	void init();			// Clear stuff during construction.
					// Move and change frame.
	void movef(Map_chunk *old_chunk, Map_chunk *new_chunk, 
		int new_sx, int new_sy, int new_frame, int new_lift);
	bool is_really_blocked(Tile_coord& t, bool force);
public:
	friend class Clear_casting;
	friend class Clear_hit;
	static void init_default_frames();	// Set usual frame sequence.
	Actor(const std::string &nm, int shapenum, int num = -1, int uc = -1);
	virtual ~Actor();
					// Blocked moving onto tile 't'?
	int is_blocked(Tile_coord& t, Tile_coord *f = 0, const int move_flags = 0);
	Game_object *find_blocking(Tile_coord tile, int dir);

	void swap_ammo(Game_object *newammo);
	bool ready_ammo();		// Find and ready appropriate ammo.
	bool ready_best_weapon();	// Find best weapon and ready it.
	bool ready_best_shield();	// Find best shield and ready it.
	void unready_weapon();		// Try to sheath weapon.
					// Force repaint of area taken.
	int get_effective_weapon_shape();//For displaying casting frames.
	int add_dirty(int figure_rect = 0);
	void change_frame(int frnum);	// Change frame & set to repaint.
	int figure_weapon_pos(int& weapon_x, int& weapon_y, int& weapon_frame);
	void use_food();		// Decrement food level.
					// Increment/decrement temperature.
	void check_temperature(bool freeze);
					// Get frame seq. for given dir.
	Frames_sequence *get_frames(int dir)
		{ return frames[dir/2]; }
	int& get_step_index()		// Get it (for updating).
		{ return step_index; }
					// Get attack frames.
	int get_attack_frames(int weapon, bool projectile,
				int dir, signed char *frames) const;
	enum Alignment {		// Describes alignment field.
		neutral = 0,
		friendly = 1,
		hostile = 2,
		unknown_align = 3 };	// Bees have this, & don't attack until
					// Spots where items are carried.
	int free_hand() const		// Get index of a free hand, or -1.
		{ 			// PREFER right hand.
		return two_handed ? -1 :
			(!spots[rhand] ? rhand : (!spots[lhand] ? lhand : -1));
		}
	int free_finger() const		// Get index of a free finger, or -1.
		{ 
		return two_fingered ? -1 :
			(!spots[lfinger] ? lfinger
			 	: (!spots[rfinger] ? rfinger : -1));
		}
	inline bool is_two_handed() const {	return two_handed; }
	inline bool is_two_fingered() const { return two_fingered; }
	inline bool is_scabbard_used() const {	return use_scabbard; }
	inline bool is_neck_used() const { return use_neck; }
	int has_light_source() const	// Carrying a torch?
		{ return light_sources > 0; }
	void add_light_source()	// Add a torch
		{ light_sources++; }
	void remove_light_source()	// Remove a torch
		{
		if (light_sources)
			light_sources--;
		}
	Attack_mode get_attack_mode()
		{ return attack_mode; }
	void set_attack_mode(Attack_mode amode, bool byuser = false)
		{ attack_mode = amode; user_set_attack = byuser; }
	bool did_user_set_attack() const
		{ return user_set_attack; }
	bool is_combat_protected() const
		{ return combat_protected; }
	void set_combat_protected(bool v)
		{ combat_protected = v; }
	int get_oppressor() const
		{ return oppressor; }
	void set_oppressor(int opp)
		{ oppressor = opp; }
	enum type_flags {
		tf_fly = 4,
		tf_walk = 5,
		tf_swim = 6,
		tf_ethereal = 7,
		tf_want_primary = 8,
		tf_sex = 9,
		tf_bleeding = 10,
		tf_in_party = 12,
		tf_in_action = 13,
		tf_conjured = 14,
		tf_summonned = 15
	};
	enum Item_properties {		// Trying to figure out properties.
		strength = 0,		// This is also max. health.
		dexterity = 1,
		intelligence = 2,
		health = 3,
		combat = 4,
		mana = 5,
		magic = 6,		// Max. mana.
		training = 7,		// Training points.
		exp = 8,		// Experience.
		food_level = 9,
		sex_flag = 10,	// Seems to be get/set sex type flag in SI.
		missile_weapon = 11	// Pretty sure it returns 1 if wearing
					// weapon with uses >= 2, 0 otherwise.
		};
	enum Frames {			// Frames 0-15.  16-31 are the same,
					//   only S instead of N.
		standing = 0,
		step_right_frame = 1,
		step_left_frame = 2,
		ready_frame = 3,	// Ready to fight?
		raise1_frame = 4,	// 1-handed strikes.
		reach1_frame = 5,
		strike1_frame = 6,
		raise2_frame = 7,	// 2-handed strikes.
		reach2_frame = 8,
		strike2_frame = 9,
		sit_frame = 10,
		bow_frame = 11,
		kneel_frame = 12,
		sleep_frame = 13,
		up_frame = 14,		// Both hands reach up.
		out_frame = 15		// Both hands reach out.
		};

	int get_face_shapenum() const	// Get "portrait" shape #.
		{ return face_num; }	// It's the NPC's #.
	int get_usecode() const
		{ return usecode == -1 ? Game_object::get_usecode() : usecode; }
	void set_usecode(int funid, const char *nm = 0)
		{
		if (funid < 0)
			{
			usecode_assigned = false;
			usecode_name.clear();
			funid = -1;
			return;
			}
		if (nm)
			usecode_name = nm;
		else
			usecode_name.clear();
		usecode = funid;
		usecode_assigned = true;
		}
	Schedule *get_schedule() const
		{ return schedule; }
	int get_frame_time() const	// Return frame time if moving.
		{ return frame_time; }
	void set_frame_time(int ftime)	// Set walking speed.
		{ frame_time = ftime; }
	void stand_at_rest();		// Stand (if not doing anyting else).
	void clear_rest_time()
		{ rest_time = 0; }
	void resting(int msecs)		// Increment rest time.
		{
		if ((rest_time += msecs) > 2000) 
			stand_at_rest();// Stand (under certain conditions).
		}
	bool is_moving() const
		{ return frame_time != 0; }
	bool is_dormant() const		// Inactive (i.e., off-screen)?
		{ return dormant; }
	bool is_dead() const
		{ return (flags&(1<<Obj_flags::dead)) != 0; }
	bool is_in_party() const	// (Includes Avatar.)
		{ return (flags&(1<<Obj_flags::in_party)) != 0; }
	void set_dormant()
		{ dormant = true; }
	Actor_action *get_action()	// Return action.
		{ return action; }
					// Set new action.
	void set_action(Actor_action *newact);
	void purge_deleted_actions();
					// Notify scheduler obj. disappeared.
	void notify_object_gone(Game_object *obj);
	Tile_coord get_dest();		// Get destination.
					// Walk to a desired spot.
	void walk_to_tile(Tile_coord dest, int speed = 250, int delay = 0,
							int maxblk = 3);
	void walk_to_tile(int tx, int ty, int tz, int speed = 250, 
					int delay = 0, int maxblk = 3)
		{ walk_to_tile(Tile_coord(tx, ty, tz), speed, delay, maxblk); }
					// Get there, avoiding obstacles.
	int walk_path_to_tile(Tile_coord src, Tile_coord dest, 
		int speed = 250, int delay = 0, int dist = 0, int maxblk = 3);
	int walk_path_to_tile(Tile_coord dest, 
		int speed = 250, int delay = 0, int dist = 0, int maxblk = 3)
		{ return walk_path_to_tile(get_tile(), dest,
						speed, delay, dist, maxblk); }
					// Start animation.
	void start(int speed = 250, int delay = 0);
	void start_std();		// Start with std. speed, delay.
	void stop();			// Stop animation.
	void follow(Actor *leader);	// Follow the leader.
					// Approach another from offscreen.
	int approach_another(Actor *other, bool wait = false);
					// Get info. about tile to step onto.
	static void get_tile_info(Actor *actor,
		Game_window *gwin, Map_chunk *nlist,
				int tx, int ty, int& water, int& poison);
					// Set combat opponent.
	void set_target(Game_object *obj, bool start_combat = false);
	Game_object *get_target()	// Get who/what we're attacking.
		{ return target; }
					// Works out if an object fits in a spot
	bool fits_in_spot (Game_object *obj, int spot);
					// The prefered slot for an object
	void get_prefered_slots (Game_object *obj, int &prefered, int &alt1, int &alt2);
					// Find where to put object.
	int find_best_spot(Game_object *obj);
	int get_prev_schedule_type();	// Get previous schedule.
	void restore_schedule();	// Set schedule after reading in.
					// Set new schedule.
	void set_schedule_type(int new_schedule_type, 
						Schedule *newsched = 0);
					// Change to new schedule at loc
	virtual void set_schedule_and_loc(int new_schedule_type, 
					Tile_coord dest, int delay = -1);
	int get_schedule_type() const
		{ return schedule_type; }
					// Get/set 'alignment'.
	int get_alignment() const
		{ return alignment; }
	void set_alignment(short a)
		{ alignment = a; }
	int get_effective_alignment() const;	// Include 'charmed' flag.
					// Update chunks after NPC moved.
	virtual void switched_chunks(Map_chunk *, Map_chunk *)
		{  }
					// Update schedule for new 3-hour time.
	virtual void update_schedule(int hour3, 
					int backwards = 0, int delay = -1)
		{  }
					// Render.
	virtual void paint();
					// Run usecode function.
	virtual void activate(int event = 1);
	virtual bool edit();		// Edit in ExultStudio.
					// Saved from ExultStudio.
	static void update_from_studio(unsigned char *data, int datalen);
					// Drop another onto this.
	virtual int drop(Game_object *obj);
	virtual std::string get_name() const;
	std::string get_npc_name() const;
	std::string get_npc_name_string() const
		{ return name; }
	void set_npc_name(const char *n);
	void set_property(int prop, int val);
	virtual bool try_to_hit(Game_object *attacker, int attval);
					// Under attack.
	virtual Game_object *attacked(Game_object *attacker, int weapon_shape = 0,
					int ammo_shape = 0, bool explosion = false);
	virtual int figure_hit_points(Game_object *attacker, int weapon_shape = -1, 
							int ammo_shape = -1, bool explosion = false);
	virtual int apply_damage(Game_object *attacker,	int str,
					int wpoints, int type, int bias = 0, int *exp = 0);
					// Lose HP's and check for death.
	virtual int reduce_health(int delta, int damage_type, Game_object *attacker = 0,
			int *exp = 0);
	void fight_back(Game_object *attacker);
	bool get_attack_target(Game_object *&obj, Tile_coord& t)
		{
		static Tile_coord invalidloc(-1, -1, 0);
		obj = target_object;
		t = target_tile;
		return (target_object || target_tile != invalidloc);
		}
	void set_attack_target(Game_object *t, int w)
		{
		target_tile = Tile_coord(-1, -1, 0);
		target_object = t;
		attack_weapon = w;
		}
	void set_attack_target(Tile_coord t, int w)
		{
		target_object = 0;
		target_tile = t;
		target_tile.fixme();
		attack_weapon = w;
		}
	virtual int get_effective_range(const Weapon_info *winf = 0, int reach = -1);
	virtual Game_object *find_weapon_ammo(int weapon, int needed = 1,
			bool recursive = false);
	Game_object *find_best_ammo(int family, int needed = 1);
	bool usecode_attack();
	int get_property(int prop) const;
	int get_effective_prop(int prop) const;
	bool is_dying() const		// Dead when health below -1/3 str.
		{ return properties[(int) health] < 
					-(properties[(int) strength]/3); }
	int get_level() const		// Get experience level.
		{ return 1 + Log2(get_property(exp)/50); }
					// Get/set generic attribute.
	void set_attribute(const char *nm, int val);
	int get_attribute(const char *nm);
	typedef std::vector<std::pair<const char *,int> > Atts_vector;
	void get_attributes(Atts_vector& attlst);
					// Set atts. from savegame.
	virtual void read_attributes(unsigned char *buf, int len);
	Npc_timer_list *need_timers();
					// Set/clear/get actor flag.
	void force_sleep();
	void clear_sleep()
		{ flags &= ~((uint32) 1 << Obj_flags::asleep); }
	virtual void set_flag(int flag);
	void set_type_flag(int flag);
	virtual void clear_flag(int flag);
	void clear_type_flag(int flag);
	int get_type_flag(int flag) const;
	void set_type_flags(unsigned short tflags);
	int get_skin_color () const { return skin_color; }
	void set_skin_color (int color) { skin_color = color; set_actor_shape();}
	virtual int get_type_flags() const
		{ return type_flags; }
	short get_casting_mode () const { return casting_mode; }
	void end_casting_mode (int delay);
	int get_casting_shape () const { return casting_shape; }
	void begin_casting (int s)
		{ casting_mode = init_casting; casting_shape = s; }
	void display_casting_frames () { casting_mode = show_casting_frames; }
	void hide_casting_frames () { casting_mode = not_casting; }
//++++++Is_dead() test messes up training.
//	unsigned char get_ident() { return is_dead() ? 0 : ident; }
	unsigned char get_ident() { return ident; }
	void set_ident(unsigned char id) { ident = id; }

	int get_temperature() const	// Get/set measure of coldness.
		{ return temperature; }
	void set_temperature(int t);
	int get_temperature_zone() const
		{
		// SI-verified.
		if (temperature < 15)
			return 1;
		else if (temperature < 25)
			return 2;
		else if (temperature < 40)
			return 3;
		else if (temperature < 50)
			return 4;
		else
			return 5;
		}
	int figure_warmth();		// Based on what's worn.
	bool is_unused() const		// Free NPC?
		{ return unused; }
	void set_unused(bool tf)
		{ unused = tf; }

	int get_npc_num() const		// Get its ID (1-num_npcs).
		{ return npc_num; }
					// Get/set index within party.
	int get_party_id() const
		{ return party_id; }
	void set_party_id(int i)
		{ party_id = i; }
					// Set for Usecode animations.
	void set_usecode_dir(int d)
		{ usecode_dir = d&7; }
	int get_usecode_dir() const
		{ return usecode_dir; }
	virtual Actor *as_actor()	// An actor?
		{ return this; }
	void init_readied();		// Call Usecode to init. readied objs.
					// Remove an object.
	virtual void remove(Game_object *obj);
					// Add an object.
	virtual bool add(Game_object *obj, bool dont_check = false,
							bool combine = false, bool noset = false);
					// Add to NPC 'readied' spot.
	virtual int add_readied(Game_object *obj, int index,
				int dont_check = 0, int force_pos = 0, bool noset = false);
	virtual int find_readied(Game_object *obj);
	virtual Game_object *get_readied(int index) const
		{
		return index >= 0 && 
			index < (int)(sizeof(spots)/sizeof(spots[0])) ? 
				spots[index] : 0; 
		}
	virtual void call_readied_usecode(int index,
					Game_object *obj, int eventid);
	virtual int get_max_weight();	// Get max. weight allowed.
					// Change member shape.
	virtual void change_member_shape(Game_object *obj, int newshape);
					// Move out of the way.
	virtual int move_aside(Actor *for_actor, int dir);
					// Get frame if rotated clockwise.
	virtual int get_rotated_frame(int quads);
	virtual int get_armor_points();	// Get total armor value.
					// Gets whether the actor is immune or vulnerable to a given
					// form of damage:
	int is_immune(int type) const;
	void refigure_gear();
	bool check_gear_powers(int flags) const
		{ return (gear_powers&flags) != 0; }
					// Get total weapon value.
	virtual Weapon_info *get_weapon(int& points, int& shape,
						Game_object *& obj);
	Weapon_info *get_weapon(int& points)
		{ int sh; Game_object *o; return get_weapon(points, sh, o); }
	static bool roll_to_win(int attacker, int defender);
					// Hit-point algorithm:
	bool can_act();
	virtual void fall_down();
	virtual void lay_down(bool die);
	virtual void die(Game_object *attacker);		// We're dead.
	Actor *resurrect(Dead_body *body);// Bring back to life.
	Monster_actor *clone();		// Create another nearby to this.
	void mend_hourly();		// Restore HP's hourly.
					// Read from file.
	void read(DataSource* nfile, int num, bool has_usecode,
							bool& fix_unused);
					// Don't write out to IREG file.
	virtual void write_ireg(DataSource* out) {  }
	virtual int get_ireg_size() { return 0; }
	void write(DataSource* nfile);// Write out (to 'npc.dat').
	virtual void write_contents(DataSource* out);	// Write contents
	void set_actor_shape(); 	// Set shape based on sex, skin color
	void set_polymorph(int shape);	// Set a polymorph shape
	void set_polymorph_default();	// Set the default shape
					// Get the polymorph shape
	int get_polymorph () { return shape_save; }
					// Get the non polymorph shape (note, doesn't returned skin coloured shapes)
					// For usecode
	int get_shape_real();	
					// This does the same, but will return skin coloured shapes
					// For paperdolls/face stats
	int get_sexed_coloured_shape() { return shape_save!=-1?shape_save:get_shapenum(); }	

	// Set schedule list.
	virtual void set_schedules(Schedule_change *list, int cnt) { }
	virtual void set_schedule_time_type(int time, int type) { }
	virtual void set_schedule_time_location(int time, int x, int y) { }
	virtual void remove_schedule(int time) { }
	virtual void get_schedules(Schedule_change *&list, int &cnt)
	{ list = NULL, cnt = 0; }

	void show_inventory();
	int inventory_shapenum();

	bool was_hit() { return hit; }

	// Should be virtual???
	void cache_out();
	bool in_usecode_control() const;
	bool quake_on_walk();
	};

/*
 *	Actor frame descriptions:
	0	Standing
	1	Walk
	2	Walk
	3	Beginning to attack
	4-6	Attacking with one hand
	7-9	Attacking with two hands
	9	Also NPC shooting magic
	10	Sitting down
	11	Bending over (beginning to sit down)
	12	Kneeling
	11	Lying down
	14	Casting spell (hands raised)
	15	Casting spell (hands outstretched)

 */

/*
 *	The main actor.
 */
class Main_actor : public Actor
	{
public:
	Main_actor(const std::string &nm, int shapenum, int num = -1, int uc = -1)
		: Actor(nm, shapenum, num, uc)
		{  frames = &avatar_frames[0]; }
					// For Time_sensitive:
	virtual void handle_event(unsigned long curtime, long udata);
	void get_followers();		// Get party to follow.
					// Step onto an (adjacent) tile.
	virtual int step(Tile_coord t, int frame, bool force = false);
					// Update chunks after NPC moved.
	virtual void switched_chunks(Map_chunk *olist,
					Map_chunk *nlist);
					// Move to new abs. location.
	virtual void move(int newtx, int newty, int newlift, int newmap = -1);
	virtual void die(Game_object *attacker);		// We're dead.
	};

/*
 *	A non-player-character that one can converse (or fight) with:
 */
class Npc_actor : public Actor
	{
	unsigned char nearby;		// Queued as a 'nearby' NPC.  This is
					//   to avoid being added twice.
protected:
	unsigned char num_schedules;	// # entries below.
	Schedule_change *schedules;	// List of schedule changes.
	int find_schedule_change(int hour3);
public:
	Npc_actor(const std::string &nm, int shapenum, int num = -1, 
								int uc = -1);
	virtual ~Npc_actor();
	void set_nearby()		// Set/clear/test 'nearby' flag.
		{ nearby = true; }
	void clear_nearby()
		{ nearby = false; }
	bool is_nearby() const
		{ return nearby!=0; }
					// Set schedule list.
	virtual void set_schedules(Schedule_change *list, int cnt);
	virtual void set_schedule_time_type(int time, int type);
	virtual void set_schedule_time_location(int time, int x, int y);
	virtual void remove_schedule(int time);
	virtual void get_schedules(Schedule_change *&list, int &cnt);
					// Move and change frame.
	void movef(Map_chunk *old_chunk, Map_chunk *new_chunk, 
		int new_sx, int new_sy, int new_frame, int new_lift);
					// Update schedule for new 3-hour time.
	virtual void update_schedule(int hour3, 
					int backwards = 0, int delay = -1);
					// Render.
	virtual void paint();
					// Run usecode function.
	virtual void activate(int event = 1);
					// For Time_sensitive:
	virtual void handle_event(unsigned long curtime, long udata);
					// Step onto an (adjacent) tile.
	virtual int step(Tile_coord t, int frame, bool force = false);
					// Remove/delete this object.
	virtual void remove_this(int nodel = 0);
					// Update chunks after NPC moved.
	virtual void switched_chunks(Map_chunk *olist,
					Map_chunk *nlist);
					// Move to new abs. location.
	virtual void move(int newtx, int newty, int newlift, int newmap = -1);

	virtual Npc_actor *as_npc() { return this; }
	};

/*
 *	An actor's dead body:
 */
class Dead_body : public Container_game_object
	{
	short npc_num;			// # of NPC it came from, or -1.
public:
	Dead_body(int shapenum, int framenum, unsigned int tilex, 
		unsigned int tiley, unsigned int lft, int n)
		: Container_game_object(shapenum, framenum, tilex, tiley, lft),
			npc_num(n)
		{
		}
	virtual ~Dead_body();
	virtual int get_live_npc_num() const;
					// Under attack.
	virtual Game_object *attacked(Game_object *attacker, int weapon_shape = 0,
					int ammo_shape = 0, bool explosion = false)
		{ return this; }	// Not affected.
	virtual void write_ireg(DataSource* out);
	virtual int get_ireg_size();
	};

#endif
